package com.autumn.platform.core.exception;

import java.lang.reflect.InvocationTargetException;
import java.util.Locale;

public abstract class Throws {

    private Throws() {};

    /**
     * 获取和异常代码对应的描述
     * 
     * @param code
     * @param args
     * @return 描述
     */
    public static String getMessage(String code, Object... args) {
        return getMessage(code, null, args);
    }

    /**
     * 获取和异常代码对应的描述
     * 
     * @param code
     * @param locale
     * @param args
     * @return 描述
     */
    public static String getMessage(String code, Locale locale, Object... args) {
        CodableException e = createException(code, null, args);
        return e.getMessage(locale);
    }

    /**
     * 抛出{@link CodableException}运行时异常
     * 
     * @param code 异常代码
     * @param args 国际化信息中的占位符参数
     * @throws CodableException 平台受检异常
     */
    public static void throwException(String code, Object... args) {
        throw createException(code, null, args);
    }

    /**
     * 抛出{@link CodableException}运行时异常
     * 
     * @param code 异常代码
     * @param e 原始异常
     * @param args 国际化信息中的占位符参数
     * @throws CodableException 平台受检异常
     */
    public static void throwException(String code, Throwable e, Object... args) {
        throw createException(code, e, args);
    }

    /**
     * 创建运行时异常
     * 
     * @param code 异常代码
     * @param args 国际化信息中的占位符参数
     * @return 运行时异常，只返回，不抛出
     */
    public static CodableException createException(String code, Object... args) {
        return createException(code, null, args);
    }

    /**
     * 创建{@link CodableException}运行时异常
     * <p>
     * <ul>
     * <li>如果传入异常或传入异常的cause为{@link CodableException}，就直接返回传入异常或传入异常的cause
     * <li>如果传入异常为{@link InvocationTargetException}，将传入异常设置为getTargetException()，再包装为{@link CodableException}运行时异常返回
     * <li>其它情况，将传入异常包装为{@link CodableException}运行时异常返回
     * </ul>
     * </p>
     * 
     * @param code 异常代码
     * @param e 原始异常
     * @param args 国际化信息中的占位符参数
     * @return {@link CodableException}运行时异常，只返回，不抛出
     */
    public static CodableException createException(String code, Throwable e, Object... args) {
        if (e instanceof CodableException) {
            return (CodableException) e;
        } else {
            Throwable cause = getRootCause(e);
            if (cause instanceof CodableException) {
                return (CodableException) cause;
            } else if (e instanceof InvocationTargetException) {
                return createException(code, ((InvocationTargetException) e).getTargetException(), args);
            } else {
                return new CodableException(code, e, args);
            }
        }
    }

    /**
     * 抛出{@link CodableException}运行时异常
     * 
     * @param code 异常代码
     * @param message 异常描述
     * @throws CodableException 平台受检异常
     */
    public static void throwCodeAndMessageException(String code, String message) {
        throw createCodeAndMessageException(code, message);
    }

    /**
     * 抛出{@link CodableException}运行时异常
     * 
     * @param code 异常代码
     * @param message 异常描述
     * @throws CodableException 平台受检异常
     */
    public static void throwCodeAndMessageException(String code, String message, Throwable e) {
        throw createCodeAndMessageException(code, message, e);
    }

    /**
     * 创建{@link CodableException}运行时异常
     * 
     * @param code 异常代码
     * @param message 异常描述
     * @return {@link CodableException}运行时异常，只返回，不抛出
     */
    public static CodableException createCodeAndMessageException(String code, String message) {
        return createCodeAndMessageException(code, message, null);
    }

    /**
     * 创建{@link CodableException}运行时异常
     * <p>
     * <ul>
     * <li>如果传入异常或传入异常的cause为{@link CodableException}，就直接返回传入异常或传入异常的cause
     * <li>如果传入异常为{@link InvocationTargetException}，将传入异常设置为getTargetException()，再包装为{@link CodableException}运行时异常返回
     * <li>其它情况，将传入异常包装为{@link CodableException}运行时异常返回
     * </ul>
     * </p>
     * 
     * @param code 异常代码
     * @param message 异常描述
     * @param e 原始异常
     * @return {@link CodableException}运行时异常，只返回，不抛出
     */
    public static CodableException createCodeAndMessageException(String code, String message, Throwable e) {
        if (e instanceof CodableException) {
            return (CodableException) e;
        } else {
            Throwable cause = getRootCause(e);
            if (cause instanceof CodableException) {
                return (CodableException) cause;
            } else if (e instanceof InvocationTargetException) {
                return createCodeAndMessageException(code, message, ((InvocationTargetException) e).getTargetException());
            } else {
                return new CodableException(code, message, e);
            }
        }
    }

    /**
     * 获取导致异常的最起初的原因
     * 
     * @param e
     * @return
     */
    public static Throwable getRootCause(Throwable e) {
        if (null == e) {
            return null;
        }
        Throwable rootCause = null;
        Throwable cause = e.getCause();
        while (cause != null && cause != rootCause) {
            rootCause = cause;
            if (e instanceof InvocationTargetException) {
                cause = ((InvocationTargetException) cause).getTargetException();
            } else {
                cause = cause.getCause();
            }
        }
        return rootCause;
    }
}
